package com.trip.file.utils;



import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import io.minio.*;
import io.minio.http.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.UUID;


@Component
@RefreshScope
public class MinioUtil {
    @Autowired
    private MinioClient minioClient;

    /**
     * 新名字
     * @param originalFilename 文件原始名称
     * @return
     */
    public String createNewFileName(String originalFilename) {
        if(StrUtil.isBlank(originalFilename)||!originalFilename.contains(".")) throw new RuntimeException(originalFilename+" not a file");
        // 获取后缀
        String suffix = StrUtil.subAfter(originalFilename, ".", true);
        // 生成目录
        String name = UUID.randomUUID().toString();
        name = StrUtil.replace(name,"-","");
        //生成文件前缀
        LocalDateTime now = LocalDateTime.now();
//        String format = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd/"));
        int year = now.getYear();
        int month = now.getMonth().getValue();
        int day = now.getDayOfMonth();

//        int hash = name.hashCode();
//        int d1 = hash & 0xF;
//        int d2 = (hash >> 4) & 0xF;

        // 生成文件名
        return StrUtil.format("{}/{}/{}/{}.{}", year, month,day, name, suffix);
    }

    /**
     * 创建桶
     *
     * @param bucketName
     */
    private void makeBucket(String bucketName) {
        try{
            BucketExistsArgs args = BucketExistsArgs.builder().bucket(bucketName).build();
            if (!minioClient.bucketExists(args)) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        }catch (Exception e){
            throw new RuntimeException("创建MinIO桶失败:"+e.getMessage());
        }
    }

    /**
     * 上传MultipartFile
     *
     * @param bucketName 桶
     * @param objectName 文件路径+文件名
     * @param file 文件
     */
    public void uploadFile(String bucketName, String objectName, MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            makeBucket(bucketName);
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(inputStream, file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build()
            );
        } catch (Exception e) {
            throw new RuntimeException("MinIO文件上传失败:" + e.getMessage());
        }
    }


    /**
     * 上传文件流
     *
     * @param objectPath  文件路径+文件名
     * @param inputStream 文件流
     * @param bucket      桶名称
     */
    public void upload(String objectPath, InputStream inputStream, String bucket) {
        try {
            makeBucket(bucket);
            minioClient.putObject(
                    PutObjectArgs
                            .builder()
                            .bucket(bucket)
                            .object(objectPath)
                            .stream(inputStream, inputStream.available(), -1)
                            .build());
        } catch (Exception e) {
            throw new RuntimeException("MinIO文件流上传失败:" + e.getMessage());
        }
    }

    /**
     * 上传文件字节数组
     *
     * @param objectPath 文件路径+文件名
     * @param byteArr    文件字节数组
     * @param bucket     桶名称
     * @return
     */
    public void upload(String objectPath, byte[] byteArr, String bucket) {
        upload(objectPath, new ByteArrayInputStream(byteArr), bucket);
    }

    /**
     * 判断文件是否存在
     *
     * @param objectPath 文件路径+文件名
     * @param bucket     桶名称
     * @return
     */
    public boolean isExists(String objectPath, String bucket) {
        boolean exist = true;
        try {
            minioClient
                    .statObject(
                            StatObjectArgs
                                    .builder()
                                    .bucket(bucket)
                                    .object(objectPath)
                                    .build());
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }

    /**
     * 下载文件字节数组
     *
     * @param bucketName 桶名称
     * @param objectName 文件路径+文件名
     * @return
     */
    public byte[] download(String bucketName, String objectName) {
        try (InputStream stream = minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()
        )) {
            return IoUtil.readBytes(stream);
        } catch (Exception e) {
            throw new RuntimeException("MinIO文件流下载失败:" + e.getMessage());
        }
    }

    /**
     * 下载文件
     * @param response 响应
     * @param objectName
     * @param bucketName
     */
    public  void downloadFile(HttpServletResponse response, String objectName, String bucketName)  {
        try {
            byte[] bytes = download(bucketName, objectName);
            response.setHeader("Content-Disposition", "attachment;filename=" + objectName);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            response.getOutputStream().write(bytes);
        } catch (Exception e) {
            throw new RuntimeException("MinIO文件流下载失败:" + e.getMessage());
        }
    }

    /**
     * 下载文件到本地
     *
     * @param objectPath 文件路径+文件名
     * @param savePath   存储目录
     * @param fileName   文件名
     * @param bucket     桶名称
     */
    public void download(String objectPath, String savePath, String fileName, String bucket) {
        try {
            File file = FileUtil.file(savePath);
            if (file.isFile()) throw new RuntimeException("savePath is not path");
            if (!file.exists()) FileUtil.mkdir(file);

            minioClient.downloadObject(DownloadObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectPath)
                    .filename(savePath + File.separator + fileName)
                    .build());
        } catch (Exception e) {
            throw new RuntimeException("MinIO文件流下载失败:" + e.getMessage());
        }
    }


    /**
     * 获取url
     * @param objectPath 文件路径+文件名
     * @param bucket 桶名称
     * @return
     */
    public String getUrl(String objectPath, String bucket) {
        try {
            String url =  minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucket)
                    .object(objectPath)
                    .build());
            url = url.substring(0, url.indexOf('?'));
            return url;
        } catch (Exception e) {
            throw new RuntimeException("获取MinIO文件地址失败:"+e.getMessage());
        }
    }

    /**
     * 通过文件名和桶名字 删除一个文件/对象
     *
     * @param objectPath 路径+文件
     * @param bucket     桶名字
     */
    public void delete(String objectPath, String bucket) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectPath)
                    .build());
        } catch (Exception e) {
            throw new RuntimeException("MinIO删除文件失败:" + e.getMessage());
        }
    }
}
